Node.js is a popular runtime platform to create programs that run on it.
It lets us run JavaScript outside the browser.
In this article, we’ll look at how to start using Node.js to create programs.
Real-Time Communication with Socket.io
Socket.io is a real-time communication library that combines HTTP requests with WebSockets to enable real-time communication in our app.
For example, we can create a simple app with Socket.io by writing:
index.js
const content = require('fs').readFileSync(__dirname + '/index.html', 'utf8');
const httpServer = require('http').createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.setHeader('Content-Length', Buffer.byteLength(content));
res.end(content);
});
const io = require('socket.io')(httpServer);
io.on('connect', socket => {
console.log('connect');
});
httpServer.listen(3000, () => {
console.log('go to http://localhost:3000');
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Minimal working example</title>
</head>
<body>
<ul id="events"></ul>
<script src="/socket.io/socket.io.js"></script>
<script>
const $events = document.getElementById('events');
const newItem = (content) => {
const item = document.createElement('li');
item.innerText = content;
return item;
};
const socket = io();
socket.on('connect', () => {
$events.appendChild(newItem('connect'));
});
</script>
</body>
</html>
In index.js
, we server the index.html
file.
Also, we listen to the connect
event to listen to any connections that are made from the client side.
In index.html
, we make the connection.
We call socket.on
to listen to connect
event to add the item when we connect to the Socket.io server.
Installation with Express
We can use Socket.io with an Express app.
To do that, we can write:
index.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const options = { /* ... */ };
const io = require('socket.io')(server, options);
io.on('connection', socket => {
console.log('connect')
});
app.use(express.static('public'));
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/index.html`);
});
server.listen(3000);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Minimal working example</title>
</head>
<body>
<ul id="events"></ul>
<script src="/socket.io/socket.io.js"></script>
<script>
const $events = document.getElementById('events');
const newItem = (content) => {
const item = document.createElement('li');
item.innerText = content;
return item;
};
const socket = io();
socket.on('connect', () => {
$events.appendChild(newItem('connect'));
});
</script>
</body>
</html>
We use the same index.html
file as before.
The only difference is that we serve it with express.
We call http
module’s createServer
method with the Express app instance instead of using a callback with it.
Then we serve the static file with the res.sendFile
method.
Namespace
We can create namespaces to segregate communication traffic.
For example, we can write:
index.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const options = { /* ... */ };
const io = require('socket.io')(server, options);
io.on('connection', socket => {
console.log('connect')
});
const adminNamespace = io.of('/admin');
adminNamespace.use((socket, next) => {
console.log(socket);
next();
});
adminNamespace.on('connection', socket => {
socket.on('delete user', (data) => {
console.log(data);
});
});
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/index.html`);
});
server.listen(3000);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Minimal working example</title>
</head>
<body>
<ul id="events"></ul>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('/admin');
socket.emit('delete user', 'foo')
</script>
</body>
</html>
In the index.js
file, we created the /admin
namespace with:
const adminNamespace = io.of('/admin');
Then we call the use
method with our own middleware function before we listen for the connections to the namespace.
We can add our logic to allow or deny the connect within the use
callback.
We call next
to finish the connection.
The adminNamespace.on
method watches the connection
event to watch for connections to the namespace.
Then we call socket.on
with the event name we want to listen to and then get the data from the data
parameter.
In index.html
, we call io('/admin')
to connect to the '/admin'
namespace.
Then we call socket.emit
with the event name as the first argument and the event data as the 2nd argument.
Conclusion
We can do real-time communication with Socket.io easily.